﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

namespace S2_Xxxx_XxxNetApi
{
    public static class XmlCommon
    {
        public static string SelectChildNodeValue(this XmlNode node, string childNode)
        {
            XmlNode n = node.SelectSingleNode(childNode);

            if (n != null)
            {
                return n.Value;
            }

            return null;
        }

        public static string SelectChildNodeText(this XmlNode node, string childNode)
        {
            XmlNode n = node.SelectSingleNode(childNode);

            if (n != null)
            {
                return n.InnerText;
            }

            return null;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="Instance"></param>
        /// <returns></returns>
        public static string ToXml(this Object Instance)
        {
            return ObjectToXML(Instance);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="strXml"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string strXml)
        {
            return XMLToObject<T>(strXml);
        }

        /// <summary>
        /// XML序列化对象
        /// </summary>
        /// <param name="emp">object that would be converted into xml</param>
        /// <returns></returns>
        public static string ObjectToXML(Object Instance)
        {
            MemoryStream stream = null;
            TextWriter writer = null;
            string ObjectXml = string.Empty;
            try
            {
                stream = new MemoryStream(); // read xml in memory
                writer = new StreamWriter(stream, Encoding.UTF8);

                // get serialise object
                Type t = Instance.GetType();
                XmlSerializer serializer = new XmlSerializer(t);

                XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                xsn.Add(string.Empty, string.Empty);

                serializer.Serialize(writer, Instance, xsn); // read object
                int count = (int)stream.Length; // saves object in memory stream
                byte[] arr = new byte[count];
                stream.Seek(0, SeekOrigin.Begin);
                // copy stream contents in byte array
                stream.Read(arr, 0, count);
                //UnicodeEncoding utf = new UnicodeEncoding(); // convert byte array to string
                UTF8Encoding utf = new UTF8Encoding();
                ObjectXml = utf.GetString(arr).Trim();
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }
            finally
            {
                if (stream != null && stream.Length > 0)
                {
                    stream.Close();
                }
                if (writer != null)
                {
                    writer.Close();
                }
            }

            return FormatXml(ObjectXml);
        }

        /// <summary>
        /// XML序列化对象
        /// </summary>
        /// <param name="Instance">实例</param>
        /// <param name="encoding">编码</param>
        /// <param name="ClearHeader">是去除声明头</param>
        /// <returns></returns>
        public static string ObjectToXML(Object Instance, Encoding encoding, bool ClearHeader)
        {
            MemoryStream stream = null;
            TextWriter writer = null;
            string ObjectXml = string.Empty;
            try
            {
                stream = new MemoryStream(); // read xml in memory
                writer = new StreamWriter(stream, encoding);

                // get serialise object
                Type t = Instance.GetType();
                XmlSerializer serializer = new XmlSerializer(t);

                XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                xsn.Add(string.Empty, string.Empty);

                serializer.Serialize(writer, Instance, xsn); // read object
                int count = (int)stream.Length; // saves object in memory stream
                byte[] arr = new byte[count];
                stream.Seek(0, SeekOrigin.Begin);
                // copy stream contents in byte array
                stream.Read(arr, 0, count);

                ObjectXml = encoding.GetString(arr).Trim();
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }
            finally
            {
                if (stream != null && stream.Length > 0)
                {
                    stream.Close();
                }
                if (writer != null)
                {
                    writer.Close();
                }
            }

            if (ClearHeader)
                return FormatXml(ObjectXml);
            else
                return ObjectXml;
        }

        /// <summary>
        /// XML序列化对象
        /// </summary>
        /// <param name="Instance">实例</param>
        /// <param name="encoding">编码</param>
        /// <returns></returns>
        public static string ObjectToXML(Object Instance, Encoding encoding)
        {
            return ObjectToXML(Instance, encoding, true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static T XMLToObject<T>(Stream stream)
        {
            XmlTextReader reader = null;
            T o = default(T);
            try
            {
                // serialise to object
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                reader = new XmlTextReader(stream);  // create reader

                //XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                //xsn.Add("xmlns", "http://tempuri.org/XMLSchema.xsd");
                // covert reader to object
                o = (T)(serializer.Deserialize(reader));
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return o;
        }

        /// <summary>
        /// 格式化XML
        /// </summary>
        /// <param name="Xml"></param>
        /// <returns></returns>
        public static string FormatXml(string Xml)
        {
            if (string.IsNullOrEmpty(Xml))
            {
                return "";
            }

            string startXml = "<?";
            string endXml = "?>";
            int startPos = Xml.IndexOf(startXml);
            int endPos = Xml.IndexOf(endXml);
            if (!(startPos == -1 || endPos == -1))
            {
                return Xml.Remove(startPos, endPos - startPos + endXml.Length);
            }
            else
            {
                return Xml;
            }
        }

        /// <summary>
        /// 反序列化XML字符串
        /// </summary>
        /// <param name="xml">xml data of employee</param>
        /// <returns></returns>
        public static object XMLToObject(string xml, Type t)
        {
            StringReader stream = null;
            XmlTextReader reader = null;
            Object o = null;
            try
            {
                // serialise to object
                XmlSerializer serializer = new XmlSerializer(t);
                stream = new StringReader(xml); // read xml data
                reader = new XmlTextReader(stream);  // create reader

                //XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                //xsn.Add("xmlns", "http://tempuri.org/XMLSchema.xsd");
                // covert reader to object
                o = serializer.Deserialize(reader);
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return o;
        }

        /// <summary>
        /// 反序列化XML字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static T FileXmlToObject<T>(string filePath)
        {
            return XMLToObject<T>(filePath, Encoding.UTF8);
        }

        /// <summary>
        /// 反序列化XML字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static T XMLToObject<T>(string filePath, Encoding encoding)
        {
            T o = default(T);
            try
            {
                using (StreamReader reader = new StreamReader(filePath, encoding))
                {
                    o = (T)XMLToObject<T>(reader.ReadToEnd());
                }
            }
            catch { }
            return o;
        }

        /// <summary>
        /// 反序列化XML字符串
        /// </summary>
        /// <param name="xml">xml data of employee</param>
        /// <returns></returns>
        public static T XMLToObject<T>(string xml)
        {
            StringReader stream = null;
            XmlTextReader reader = null;
            T o = default(T);
            try
            {
                // serialise to object
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                stream = new StringReader(xml); // read xml data
                reader = new XmlTextReader(stream);  // create reader

                //XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                //xsn.Add("xmlns", "http://tempuri.org/XMLSchema.xsd");
                // covert reader to object
                o = (T)(serializer.Deserialize(reader));
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
                if (reader != null)
                {
                    reader.Close();
                }
            }

            return o;
        }

        /// <summary>
        /// 将对象序列化为xml
        /// </summary>
        /// <param name="o">要序列化的对象</param>
        /// <param name="t">对象类型</param>
        /// <returns></returns>
        public static string SerializableObjectToXml(object o, Type t)
        {
            System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(t);
            System.IO.MemoryStream mem = new System.IO.MemoryStream();
            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(mem, Encoding.GetEncoding("UTF-16"));

            xs.Serialize(writer, o);
            writer.Close();
            return Encoding.GetEncoding("UTF-16").GetString(mem.ToArray());
        }

        /// <summary>
        /// 将对象序列化为xml
        /// </summary>
        /// <param name="o">要序列化的对象</param>
        /// <param name="t">对象类型</param>
        /// <param name="encoding">编码</param>
        /// <returns></returns>
        public static string SerializableObjectToXml(object o, Type t, Encoding encoding)
        {
            System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(t);
            System.IO.MemoryStream mem = new System.IO.MemoryStream();
            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(mem, encoding);

            xs.Serialize(writer, o);
            writer.Close();
            return encoding.GetString(mem.ToArray());
        }

        /// <summary>
        /// 将xml反序列化为对象
        /// </summary>
        /// <param name="xmlString">原始XML字符串</param>
        /// <param name="t">反序列化的对象类型</param>
        /// <returns></returns>
        public static object DeserializeXmlToObject(string xmlString, Type t)
        {
            System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(t);
            System.IO.StreamReader mem = new System.IO.StreamReader(new System.IO.MemoryStream(System.Text.Encoding.GetEncoding("UTF-16").GetBytes(xmlString)), System.Text.Encoding.GetEncoding("UTF-16"));
            System.Xml.XmlReader xr = System.Xml.XmlReader.Create(mem);
            object o = xs.Deserialize(xr);
            return o;
        }

        /// <summary>
        /// 将xml反序列化为对象
        /// </summary>
        /// <param name="xmlString">原始XML字符串</param>
        /// <param name="t">反序列化的对象类型</param>
        /// <param name="encoding">编码</param>
        /// <returns></returns>
        public static object DeserializeXmlToObject(string xmlString, Type t, Encoding encoding)
        {
            System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(t);
            System.IO.StreamReader mem = new System.IO.StreamReader(new System.IO.MemoryStream(encoding.GetBytes(xmlString)), encoding);
            System.Xml.XmlReader xr = System.Xml.XmlReader.Create(mem);
            object o = xs.Deserialize(xr);
            return o;
        }

        /// <summary>
        /// 修改 XML 中声明 encoding 属性为指定的 Encoding Name
        /// </summary>
        /// <param name="Xml"></param>
        /// <param name="EncodingName"></param>
        /// <returns></returns>
        public static string ChangeXMLEncoding(string Xml, string EncodingName)
        {
            return Regex.Replace(Xml, "(?<1><\\?xml[^?]*encoding=\"?)[^\"?]+(?<2>\\b\"?)[^?]*(?<3>\\?>)", "$1" + EncodingName + "$2$3", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        /// <summary>
        /// 把对象实例序列化成指定编码的XML字符串
        /// </summary>
        /// <param name="Instance"></param>
        /// <param name="EncodingName"></param>
        /// <returns></returns>
        public static string ObjectToXMLByEnCoding(object Instance, Encoding MsgEncoding)
        {
            //Instance = null;
            MemoryStream stream = null;
            TextWriter writer = null;

            string xmlstr = string.Empty;
            try
            {
                stream = new MemoryStream(); // read xml in memory
                writer = new StreamWriter(stream, MsgEncoding);

                // get serialise object
                XmlSerializer serializer = new XmlSerializer(Instance.GetType());

                XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
                xsn.Add(string.Empty, string.Empty);

                serializer.Serialize(writer, Instance, xsn); // read object
                int count = (int)stream.Length; // saves object in memory stream
                byte[] arr = new byte[count];
                stream.Seek(0, SeekOrigin.Begin);
                // copy stream contents in byte array
                stream.Read(arr, 0, count);

                xmlstr = MsgEncoding.GetString(arr).Trim();
                arr = null;
            }
            catch
            {
                xmlstr = "";
            }
            finally
            {
                if (stream != null && stream.Length > 0)
                {
                    stream.Close();
                }
                if (writer != null)
                {
                    writer.Close();
                }
            }
            //return ConvertEncoding.Replace( xmlstr, "$1GBK$2$3" );
            return xmlstr;
        }
    }
}
